#pragma region Licensing
/*
       LOGL::GLib -> LorgonJortle's OpenGL Game Library
       Copyright (C) 2011  Jesse 'LorgonJortle' Wilkerson

       This program is free software: you can redistribute it and/or modify
       it under the terms of the GNU General Public License as published by
       the Free Software Foundation, either version 3 of the License, or
       (at your option) any later version.

       This program is distributed in the hope that it will be useful,
       but WITHOUT ANY WARRANTY; without even the implied warranty of
       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       GNU General Public License for more details.

       You should have received a copy of the GNU General Public License
       along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#pragma endregion

#include "Mouse.h"

namespace LOGL_GLib
{
     namespace Input
     {
          /* Declare the static members in this scope. */
          GLuint Mouse::x = 0;
          GLuint Mouse::y = 0;
          GLint Mouse::scroll = 0;
          GLboolean Mouse::buttons[3] = { GL_FALSE };
          GLboolean Mouse::previousButtons[3] = { GL_FALSE };
          GLvoid (*Mouse::clickFunc)(MouseButton _Button, MouseButtonState _State) = 0;
          GLvoid (*Mouse::motionFunc)(GLint _X, GLint _Y, GLint _DeltaX, GLint _DeltaY) = 0;

           /******************************************************************************
           static Vector2 Mouse::Position();
                    Arguments:
                         void

                    Description:
                         Gets the current mouse position.

                    Returns:
                         The current mouse position.
          *******************************************************************************/
          Vector2 Mouse::Position()
          {
               return Vector2(x, y);
          }

           /******************************************************************************
           static GLuint Mouse::X();
                    Arguments:
                         void

                    Description:
                         Gets the current mouse X position.

                    Returns:
                         The current mouse X position.
          *******************************************************************************/
          GLuint Mouse::X()
          {
               return x;
          }

           /******************************************************************************
           static GLuint Mouse::Y();
                    Arguments:
                         void

                    Description:
                         Gets the current mouse Y position.

                    Returns:
                         The current mouse Y position.
          *******************************************************************************/
          GLuint Mouse::Y()
          {
               return y;
          }

          /******************************************************************************
           static GLint Mouse::Scroll();
                    Arguments:
                         void

                    Description:
                         Gets the scroll value for the mouse.

                    Returns:
                         The scroll value for the mouse.
          *******************************************************************************/
          GLint Mouse::Scroll()
          {
               return scroll;
          }

          /******************************************************************************
           static GLboolean Mouse::IsButtonDown(MouseButton _Button);
                    Arguments:
                         MouseButton _Button:
                              The button to test.

                    Description:
                         Gets whether or not the specified mouse button is down.

                    Returns:
                         Whether or not the specified button is down.
          *******************************************************************************/
          GLboolean Mouse::IsButtonDown(MouseButton _Button)
          {
               return buttons[_Button];
          }

          /******************************************************************************
           static GLboolean Mouse::IsNewButtonDown(MouseButton _Button);
                    Arguments:
                         MouseButton _Button:
                              The button to test.

                    Description:
                         Gets whether or not the specified button is pressed, but was not
                         pressed last update.

                    Returns:
                         Whether or not the specified button is pressed, but was not pressed
                         last update.
          *******************************************************************************/
          GLboolean Mouse::IsNewButtonDown(MouseButton _Button)
          {
               return buttons[_Button] && !previousButtons[_Button];
          }

          /******************************************************************************
           static GLvoid Mouse::SwapBuffers();
                    Arguments:
                         void

                    Description:
                         Swaps the current and previous button state buffers.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Mouse::SwapBuffers()
          {
               /* Set the previous state to the current state. */
               previousButtons[0] = buttons[0];
               previousButtons[1] = buttons[1];
               previousButtons[2] = buttons[2];
          }

          /******************************************************************************
           static GLvoid Mouse::ClickFunc(GLvoid (*_clickFunc)(MouseButton _Button,
                                                       MouseButtonState _State));
                    Arguments:
                         GLvoid (*_clickFunc)(MouseButton _Button, MouseButtonState _State):
                              A function pointer to set as a callback.

                    Description:
                         Sets the mouse click callback.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Mouse::ClickFunc(GLvoid (*_clickFunc)(MouseButton _Button, MouseButtonState _State))
          {
               clickFunc = _clickFunc;
          }

          /******************************************************************************
           static GLvoid Mouse::MotionFunc(GLvoid (*_motionFunc)(GLint _X, GLint _Y,
                                                         GLint _DeltaX, GLint _DeltaY));
                    Arguments:
                         GLvoid (*_motionFunc)(GLint _X, GLint _Y, GLint _DeltaX,
                         GLint _DeltaY):
                              A function pointer to set as a callback.

                    Description:
                         Sets the mouse motion callback.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Mouse::MotionFunc(GLvoid (*_motionFunc)(GLint _X, GLint _Y, GLint _DeltaX, GLint _DeltaY))
          {
               motionFunc = _motionFunc;
          }

          /******************************************************************************
           static GLvoid Mouse::Click(GLint _Button, GLint _State);
                    Arguments:
                         GLint _Button:
                              The button that triggered an action.
                         GLint _State:
                              The state of the button.

                    Description:
                         Changes mouse state to represent the button action.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Mouse::Click(GLint _Button, GLint _State)
          {
               /* Update the buffer. */
               switch (_State)
               {
                    case Mouse_Pressed:
                    {
                         if(_Button == Mouse_Left)
                              buttons[Mouse_Left] = GL_TRUE;
                         else if(_Button == Mouse_Middle)
                              buttons[Mouse_Middle] = GL_TRUE;
                         else if(_Button == Mouse_Right)
                              buttons[Mouse_Right] = GL_TRUE;
                         else if(_Button == Mouse_Scroll_Up)
                              scroll++;
                         else if(_Button == Mouse_Scroll_Down)
                              scroll--;
                    } break;

                    case Mouse_Released:
                    {
                         if(_Button == Mouse_Left)
                              buttons[Mouse_Left] = GL_FALSE;
                         else if(_Button == Mouse_Middle)
                              buttons[Mouse_Middle] = GL_FALSE;
                         else if(_Button == Mouse_Right)
                              buttons[Mouse_Right] = GL_FALSE;
                    } break;

                    default:
                         break;
               }

               /* Acknowledge any callback. */
               if(clickFunc != 0)
                    clickFunc((MouseButton)_Button, (MouseButtonState)_State);
          }

          /******************************************************************************
           static GLvoid Mouse::Motion(GLint _X, GLint _Y, GLint _DeltaX, GLint _DeltaY);
                    Arguments:
                         GLint _X:
                              The new X position of the mouse.
                         GLint _Y:
                              The new Y position of the mouse.
                         GLint _DeltaX:
                              The change in X.
                         GLint _DeltaY:
                              The change in Y.

                    Description:
                         Updates the mouse's position state.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Mouse::Motion(GLint _X, GLint _Y, GLint _DeltaX, GLint _DeltaY)
          {
               x = _X;
               y = _Y;

               /* Acknowledge any callback. */
               if(motionFunc != 0)
                    motionFunc(_X, _Y, _DeltaX, _DeltaY);
          }

          /******************************************************************************
           static GLvoid Mouse::ToggleCursor();
                    Arguments:
                         void

                    Description:
                         Toggles the visibility of the cursor.

                    Returns:
                         void
          *******************************************************************************/
          GLvoid Mouse::ToggleCursor()
          {
               /* Set the mouse to the opposite of what it was. */
               SDL_ShowCursor(!SDL_ShowCursor(SDL_QUERY));
          }

     } /* Namespace Input. */
} /* Namespace LOGL_GLib. */
